package com.tanhua.server.service;

import cn.hutool.core.collection.CollectionUtil;
import com.github.tobato.fastdfs.domain.conn.FdfsWebServer;
import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.tanhua.autoconfig.template.OssTemplate;
import com.tanhua.commons.constant.Constants;
import com.tanhua.dubbo.api.db.UserInfoApi;
import com.tanhua.dubbo.api.mongo.VideoApi;
import com.tanhua.model.db.UserInfo;
import com.tanhua.model.mongo.Video;
import com.tanhua.model.vo.PageResult;
import com.tanhua.model.vo.VideoVo;
import com.tanhua.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class VideoService {

    //从调度服务器获取，一个目标存储服务器，上传
    @Autowired
    private FastFileStorageClient client;

    @Autowired
    private FdfsWebServer webServer;// 获取存储服务器的请求URL

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private VideoApi videoApi;

    @DubboReference
    private UserInfoApi userInfoApi;

    /**
     * 发布小视频
     * @param videoThumbnail
     * @param videoFile
     */
    // 发布小视频时，要删除缓存, 有可能会造成 缓存雪崩
    @CacheEvict(value = "videos", allEntries = true)
    public void publish(MultipartFile videoThumbnail, MultipartFile videoFile) {
        //1. 先上传视频文件到fastdfs上
        // 获取文件后缀名
        String filename = videoFile.getOriginalFilename();
        //不加1得到的是.mp4,我们不需要.，所以要+1
        String suffix = filename.substring(filename.lastIndexOf(".") + 1);
        try {
            StorePath storePath = client.uploadFile(videoFile.getInputStream(), videoFile.getSize(), suffix, null);
            // 视频的完整路径
            String videoUrl = webServer.getWebServerUrl() + storePath.getFullPath();
            //2. 上传封面图片到oss上
            String picUrl = ossTemplate.upload(videoThumbnail.getOriginalFilename(), videoThumbnail.getInputStream());
            //3. 构建pojo
            Video pojo = new Video();
            pojo.setUserId(UserHolder.getUserId());
            pojo.setVideoUrl(videoUrl);
            pojo.setPicUrl(picUrl);
            pojo.setText("黑马出品");
            //4. 调用api保存
            videoApi.add(pojo);
        } catch (IOException e) {
            //e.printStackTrace();
            log.error("上传小视频失败",e);
        }
    }

    /**
     * 小视频列表
     * @param page
     * @param pageSize
     * @return
     * videos::用户id_page_pagesize
     * videos::1_1_10
     */
    @Cacheable(value = "videos",
            key = "T(com.tanhua.server.interceptor.UserHolder).getUserId() + '_' + #page + '_' + #pageSize")
    public PageResult<VideoVo> findPage(Long page, Long pageSize) {
        log.debug("进入了findPage方法: {},{},{}", UserHolder.getUserId(), page, pageSize);
        List<Video> videoList = new ArrayList<>();
        List<VideoVo> voList = new ArrayList<>();
        //1. 先查询推荐 vid 以逗号分割
        //1.1 拼接redis中推荐的key,
        String key = Constants.VIDEOS_RECOMMEND + UserHolder.getUserId();
        String vidString = stringRedisTemplate.opsForValue().get(key);
        //1.2 按逗号分割，得到数组，得数组的长度  15
        long redisPages = 0;
        String[] vidArr = StringUtils.split(vidString, ",");
        //1.3 数组的长度>start, 推荐数据的分页报告表
        long total = 0;
        if(null != vidArr) {
            total = vidArr.length;
            long start = (page - 1) * pageSize;
            // redis推荐的页数
            redisPages = total % pageSize == 0 ? total / pageSize : total / pageSize + 1;
            if (total > start) {
                //1.4 获得推荐的vid，通过推荐vid查询视频信息
                List<Long> vids = Arrays.stream(vidArr).skip(start).limit(pageSize).map(Long::valueOf).collect(Collectors.toList());
                //3. 得到视频列表数据后
                videoList = videoApi.findByVids(vids);
            }
        }
        //2. 推荐查完了，再查询数据库最新的
        if(CollectionUtil.isEmpty(videoList)) {
            //如果有，则要去掉推荐中的页数。数据库的查询应该从第一页开始
            PageResult pageResult = videoApi.findPage(page - redisPages, pageSize);
            // 累加, 用户看到是一致的
            total += pageResult.getCounts();
            //3. 得到视频列表数据后
            videoList = pageResult.getItems();
        }
        if(CollectionUtil.isNotEmpty(videoList)) {
            //4. 取出所有作者id
            List<Long> userIds = videoList.stream().map(Video::getUserId).collect(Collectors.toList());

            //5. 查询作者信息
            Map<Long, UserInfo> userInfoMap = userInfoApi.findByBatchIds(userIds, null);
            //6. 转成vo
            voList = videoList.stream().map(v -> VideoVo.init(userInfoMap.get(v.getUserId()), v)).collect(Collectors.toList());
            // 当前登录用户是否关注了这个作者
            /*voList.forEach(vo->{
                String authorKey = Constants.FOCUS_USER_KEY + vo.getUserId();
                // 是否关注作者。
                if (stringRedisTemplate.opsForSet().isMember(authorKey, UserHolder.getUserId().toString())) {
                    vo.setHasFocus(1);
                }
            });*/
        }
        //7. 设置到pageResult，再返回 1
        return new PageResult<VideoVo>(page, pageSize, total, voList);
    }
}
